package ssau.knyazev.fft.modules.threads;

import java.util.concurrent.CyclicBarrier;

import ssau.knyazev.core.Complex;

public class ComplexThread implements Runnable{

	protected int idx;
	protected int idy;
	protected int uid;
	protected int blockX;
	protected int blockY;
	private Complex[][] data = null;
	private CyclicBarrier barrier = null;
	private Complex[] wlist = null;

	public ComplexThread(CyclicBarrier barrier, int idx, int idy, int blockX, int blockY, Complex[][] data, Complex[] wlist){
		this.idx = idx;
		this.idy = idy;
		this.uid = idy*blockX + idx;
		this.barrier = barrier;
		this.data = data;
		this.wlist = wlist;
		this.blockY = blockY;
		this.blockX = blockX;
	}
	
	public void run() {
		int N = data.length;
		int step, step2;
		int size = 0;
		for (int x = data.length; x > 1; x = x >> 1){
			size++;
		}
		boolean flag;
		for (int q = 0; q < size-1; q++) {
			step = (int)Math.pow(2, q);
			step2 = step*2;
			for (int down = idx*N/blockX; down < ((idx+1)*N/blockX) - step; down++) {
				for (int right = idy*N/blockY; right < ((idy+1)*N/blockY) - step; right++) {
					flag = (down/step) % 2 + (right/step) % 2 > 0 ? false : true;
					if (flag){
						Complex w1 = wlist[(down % step2)*(N/step2)];
						Complex w2 = wlist[(right % step2)*(N/step2)];
						butterfly(data[down][right], data[down][right+step], data[down+step][right], data[down+step][right+step], w1, w2);
					}
				}
			}
		}
		try {
			barrier.await();
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		if (idx == 0 && idy == 0){
			step = (int)Math.pow(2, size-1);
			step2 = step*2;
			for (int down = 0; down < N - step; down++) {
				for (int right = 0; right < N - step; right++) {
					flag = (down/step) % 2 + (right/step) % 2 > 0 ? false : true;
					if (flag){
						Complex w1 = wlist[(down % step2)*(N/step2)];
						Complex w2 = wlist[(right % step2)*(N/step2)];
						butterfly(data[down][right], data[down][right+step], data[down+step][right], data[down+step][right+step], w1, w2);
					}
				}
			}
		}
	}
	
	protected static void butterfly(Complex a00, Complex a01, Complex a10, Complex a11, Complex w1, Complex w2) {
		Complex newa00 = new Complex();
		Complex newa01 = new Complex();
		Complex newa10 = new Complex();
		Complex newa11 = new Complex();
		Complex t = null;

		newa00 = newa00.add(a00);
		newa10 = newa10.add(a00);
		newa01 = newa01.add(a00);
		newa11 = newa11.add(a00);
		
		t = w1.multy(a10);
		newa00 = newa00.add(t);
		newa10 = newa10.sub(t);
		newa01 = newa01.add(t);
		newa11 = newa11.sub(t);
		
		t = w2.multy(a01);
		newa00 = newa00.add(t);
		newa10 = newa10.add(t);
		newa01 = newa01.sub(t);
		newa11 = newa11.sub(t);
		
		t = w1.multy(w2.multy(a11));
		newa00 = newa00.add(t);
		newa10 = newa10.sub(t);
		newa01 = newa01.sub(t);
		newa11 = newa11.add(t);
		
		copyValues(a00, newa00);
		copyValues(a01, newa01);
		copyValues(a10, newa10);
		copyValues(a11, newa11);
	}
	
	protected static void copyValues(Complex a, Complex b) {
		a.setReal(b.getReal());
		a.setImg(b.getImg());
	}
	
}